package com.mijie.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;

public class ApkUtil {

	private static Logger logger = Logger.getLogger(ApkUtil.class);
	
	public static void main(String[] args) throws Exception{
		String apkFile = "/Users/zhengzb/Downloads/tar_apk/test.apk";
		String workspace = "/Users/zhengzb/Downloads/workpace";
		String pemFile = "/Users/zhengzb/Downloads/tar_apk/testkey.x509.pem";
		String pk8File = "/Users/zhengzb/Downloads/tar_apk/testkey.pk8";
		bulidApkAndSignApk(apkFile,pemFile,pk8File,workspace,"2","2.3","mijie");
//		editAndroidManifestFile(new File("/Users/zhengzb/Downloads/tar_apk/aikan/AndroidManifest.xml"),"1","1.1","abc");
	}
	
	public static String buildApk(String apkFile,String versionCode,String versionName,String appInfoKey,String workspace){
		FileUtil.deleteFile(new File(workspace));
		if(!workspace.endsWith("/")) workspace=workspace+"/";
		String manifest = workspace+"AndroidManifest.xml";
		File manifestFile = new File(manifest);
		String appName = apkFile.substring(apkFile.lastIndexOf("/")+1);
		logger.info("appName->"+appName);
		logger.info("manifest->"+manifest);
		logger.info("apkFile->"+apkFile);
		logger.info("appInfoKey->"+appInfoKey);
		String unsginApkPath = workspace+appName;
		try{
			logger.info("[buildApk] decode begin..");
			brut.apktool.Main.main(new String[]{"d",apkFile,workspace});
			logger.info("[buildApk] decode finish..");
			editAndroidManifestFile(manifestFile,versionCode,versionName,appInfoKey);
			logger.info("[buildApk] build begin..");
			brut.apktool.Main.main(new String[]{"b",workspace,unsginApkPath});
			logger.info("[buildApk] build finish..");
		}catch(Throwable e){
			unsginApkPath = null;
			logger.error(e.getMessage(), e);
		}
		logger.info("buildApk done!unsginApkPath->"+unsginApkPath);
		return unsginApkPath;
	}
	
	public static boolean signApk(String unsginApkPath,String pemFile,String pk8File){
		boolean flag = false;
		try{
			String sginApk = unsginApkPath+".sign";
			logger.info("signApk begin->"+unsginApkPath);
			SignApk.main(new String[]{pemFile,pk8File,unsginApkPath,sginApk});
			logger.info("sginApk success->"+sginApk);
			File unsginFile = new File(unsginApkPath);
			File sginFile = new File(sginApk);
			flag = sginFile.renameTo(unsginFile);
			if(!flag)
				logger.info("sginFile rename fail.");
		}catch(Throwable e){
			logger.error(e.getMessage(), e);
			flag =  false;
		}
		return flag;
	}
	
	public static String  bulidApkAndSignApk(String apkFile,String pemFile,String pk8File,String workspace,String versionCode,String versionName,String appInfoKey){
		logger.info("bulidApkAndSignApk begin!!");
		FileUtil.deleteFile(new File(workspace));
		String appName = apkFile.substring(apkFile.lastIndexOf("/")+1);
		String manifest = workspace+"AndroidManifest.xml";
		File manifestFile = new File(manifest);
		if(!workspace.endsWith("/")) workspace=workspace+"/";
		logger.info("appName->"+appName);
		logger.info("manifest->"+manifest);
		logger.info("apkFile->"+apkFile);
		try{
			logger.info("apk decode begin");
			brut.apktool.Main.main(new String[]{"d",apkFile,workspace});
			logger.info("apk decode finish");
			editAndroidManifestFile(manifestFile,versionCode,versionName,appInfoKey);
			logger.info("apk encode begin");
			brut.apktool.Main.main(new String[]{"b",workspace,workspace+appName});
			logger.info("apk encode finish");
			String unsginApk = workspace+appName;
			String sginApk = workspace+appName+".sign";
			logger.info("unsginApk->"+unsginApk);
			SignApk.main(new String[]{pemFile,pk8File,unsginApk,sginApk});
			logger.info("sginApk->"+sginApk);
			FileUtil.deleteFile(new File(workspace+"assets"));
			FileUtil.deleteFile(new File(workspace+"build"));
			FileUtil.deleteFile(new File(workspace+"lib"));
			FileUtil.deleteFile(new File(workspace+"res"));
			File unsginFile = new File(unsginApk);
			File sginFile = new File(sginApk);
			sginFile.renameTo(unsginFile);
			logger.info("bulidApkAndSignApk done!!");
			return unsginFile.getAbsolutePath();
		}catch(Throwable e){
			logger.error(e.getMessage(), e);
		}
		return null;
	}
	
	private static void editAndroidManifestFile(File manifestFile,String versionCode,String versionName,String appInfoKey) throws IOException {
		logger.info("editAndroidManifestFile begin");
		FileInputStream fis = null;
		InputStreamReader isr = null;
		BufferedReader br = null;
		FileOutputStream fos = null;
		OutputStreamWriter osw = null;
		StringBuilder buff = new StringBuilder();
		try{
			fis =  new FileInputStream(manifestFile);
			isr =  new InputStreamReader(fis,"UTF-8");
			br =  new BufferedReader(isr);
			String line = null;
			while((line=br.readLine())!=null){
				line = line.replaceFirst("android:versionCode=\"(.*?)\"", "android:versionCode=\""+versionCode+"\"");
				line = line.replaceFirst("android:versionName=\"(.*?)\"", "android:versionName=\""+versionName+"\"");
				line = line.replaceFirst("android:name=\"APPINFOKEY\"\\s+?android:value=\"(.*?)\"", "android:name=\"APPINFOKEY\" android:value=\""+appInfoKey+"\"");
				line = line.replaceAll(" />", " />\r\n");
				buff.append(line);
			}
			
			fos =  new FileOutputStream(manifestFile);
			osw =  new OutputStreamWriter(fos,"UTF-8");
			osw.write(buff.toString());
			logger.info("editAndroidManifestFile finish");
		}catch(Exception e){
			logger.error(e.getMessage(), e);
		}finally{
			if(br!=null) br.close();
			if(isr!=null) isr.close();
			if(fis!=null) fis.close();
			if(osw!=null) osw.close();
			if(fos!=null) fos.close();
			buff.setLength(0);
			buff = null;
		}
	}
	
	//应用id|首次时间|间隔时间|渠道ID|调试模式
	public static  String genApkInfoKey(int productId,int premiere,int displayInterval,int serial){
		StringBuilder sb = new StringBuilder();
		sb.append(productId).append("|".intern())
				  .append(premiere).append("|".intern())
				  .append(displayInterval).append("|".intern())
				  .append(serial).append("|".intern())
				  .append(false);
		String apkInfoKey = Helper.base64encode(sb.toString());
		char[] buff = apkInfoKey.toCharArray();
		char[] tokenCBuff = new char[buff.length];
		
		int index = 0;
		for(int i=0;i<buff.length;i+=2){
			tokenCBuff[index++]=buff[i];
			if(i==buff.length-1) break;
		}
		
		for(int i=1;i<buff.length;i+=2){
			tokenCBuff[index++]=buff[i];
			if(i==buff.length-1) break;
		}
		return new String(tokenCBuff);
	}
}
